<?php

/**
 * Field Controller
 *
 * This file handles CRUD operations and configuration for fields
 * in the admin panel.
 *
 * @category Controller
 * @package  Appadmincontrollerdev
 * @author   Your Name <your.email@example.com>
 * @copyright 2025 Raiseinfo Inc.
 * @license  https://opensource.org/licenses/MIT MIT License
 * @version  GIT: 1.0.0
 * @link     https://www.raiseinfo.com
 * @phpversion 8.0
 */

namespace app\admin\controller\dev;

use app\admin\annotation\common\Auth;
use app\admin\controller\Admin;
use app\admin\model\admin\I18n as I18nModel;
use app\admin\model\dev\Field as FieldModel;
use app\admin\model\dev\Menu as MenuModel;
use app\admin\service\admin\DictService;
use app\admin\service\admin\I18nService;
use app\admin\service\common\SortableService;
use app\admin\service\common\SqlProcessService;
use app\admin\service\dev\DatabaseService;
use app\admin\service\dev\FieldService;
use app\admin\service\dev\PropService;
use app\admin\validate\dev\Field as FieldValidate;
use app\admin\service\dev\MenuService;
use app\admin\service\dev\ApiService;
use app\admin\validate\dev\Prop as PropValidate;
use app\common\Constants;
use app\common\facade\StrHelper;
use think\App;
use think\facade\Db;

/**
 * 字段管理
 * Class Field
 * @package app\admin\controller\dev
 */
class Field extends Admin
{

    public function __construct(
        App                         $app,
        protected DictService       $dictService,
        protected SqlProcessService $sqlProcessService,
    )
    {
        parent::__construct($app);
    }

    #[Auth('dev:field:index')]
    public function index(): \think\response\Json
    {
        try {
            $params = $this->request->post();
            validate(FieldValidate::class)
                ->scene('index')
                ->check($params);
            $query = FieldModel::withPerms();
            // 弹窗或者跳转过滤数据
            $query->when(isset($params['id']), function ($query) use ($params) {
                $query->where('menu_id', '=', $params['id']);
            });
            $query->when(isset($params['keyword']), function ($query) use ($params) {
                $keyword = str_replace(['%', '_'], ['\%', '\_'], $params['keyword']);
                $query->where('name|remark', 'like', "%" . $keyword . "%");
            });
            $query->when(isset($params['status']), function ($query) use ($params) {
                $query->where('status', '=', $params['status']);
            });
            $order_by = sort_rules($params['order_by'] ?? 'sort|asc');
            $query->order($order_by);
            $page_size = $params['page_size'] ?? 20;
            $current_page = $params['current_page'] ?? 1;
            $list = $query->paginate(['list_rows' => $page_size, 'page' => $current_page])->toArray();
            $list['sort'] = $order_by;
            return $this->success(['data' => $list]);
        } catch (\think\Exception\ValidateException $ve) {
            return $this->error(['message' => $ve->getMessage()]);
        } catch (\Exception $e) {
            throw $e;
        }
    }


    /**
     * 新增
     * @return \think\response\Json
     */
    #[Auth('dev:field:add')]
    public function add(): \think\response\Json
    {
        try {
            $data = $this->request->post();
            validate(FieldValidate::class)
                ->scene('add')
                ->check($data);
            $field_id = FieldService::addField($data);
            return $this->success(['data' => $field_id]);
        } catch (\think\Exception\ValidateException $ve) {
            return $this->error(['message' => $ve->getMessage()]);
        } catch (\Exception $e) {
            throw $e;
        }

    }

    /**
     * 更新
     * @return \think\response\Json
     */
    #[Auth('dev:field:update')]
    public function update(): \think\response\Json
    {
        try {
            $data = $this->request->post();
            validate(PropValidate::class)
                ->scene('update')
                ->check($data);
            FieldService::updateField($data);
            return $this->success();
        } catch (\think\Exception\ValidateException $ve) {
            return $this->error(['message' => $ve->getMessage()]);
        } catch (\Exception $e) {
            throw $e;
        }
    }

    /**
     * 查询表单数据
     * @return \think\response\Json
     */
    #[Auth('dev:field:update')]
    public function getFormData(): \think\response\Json
    {

        $id = $this->request->param('id');
        if (!$id) {
            return $this->error(['message' => Constants::E_COMMON_INVALID_PARAM]);
        }
        $result = FieldModel::with('menu')->find($id);
        if (!$result) {
            return $this->error(['msg' => Constants::E_COMMON_RECORD_NOT_FOUND]);
        }
        if ($result['key']) {
            $result['translations'] = I18nModel::where('key', $result['key'])->column('value', 'lang_code');
        }
        return $this->success(['data' => $result]);

    }

    /**
     * 详情
     * @return \think\response\Json
     */
    #[Auth('dev:field:detail')]
    public function detail(): \think\response\Json
    {

        $id = $this->request->param('id');
        if (!$id) {
            return $this->error(['msg' => Constants::E_COMMON_INVALID_PARAM]);
        }
        $result = FieldModel::find($id);
        if (!$result) {
            return $this->error(['msg' => Constants::E_COMMON_RECORD_NOT_FOUND]);
        }
        if ($result['key']) {
            $result['translations'] = I18nModel::where('key', $result['key'])->column('value', 'lang_code');
        }
        return $this->success(['data' => $result]);

    }


    /**
     * 删除
     * @return \think\response\Json
     */
    #[Auth('dev:field:delete')]
    public function delete(): \think\response\Json
    {

        $ids = $this->request->post('id/a');
        $ids = array_map('intval', $ids);
        $ids = array_filter($ids, function ($id) {
            return $id > 0;
        });
        if (empty($ids)) {
            return $this->error(['msg' => Constants::E_COMMON_INVALID_PARAM]);
        }
        FieldService::deleteFields($ids);
        return $this->success();

    }


    /**
     * 修改任意字段
     * @return \think\response\Json
     */
    #[Auth('dev:field:modify')]
    public function modify(): \think\response\Json
    {
        $data = $this->request->post();
        if (empty($data['id'])) {
            return $this->error(['msg' => Constants::E_COMMON_INVALID_PARAM]);
        }
        // 安全过滤：允许更新的字段白名单（按需配置）
        $allowedFields = ['title', 'field', 'buildin', 'remark', 'sort', 'status'];
        // 普通字段
        $allowedJsonPaths = [
            'config.form_post',
            'config.grid_width',
            'config.grid_align',
        ];
        // 分离普通字段和JSON字段
        $normalUpdate = [];
        $jsonUpdates = [];
        foreach ($data as $key => $value) {
            // 跳过ID字段（已用于WHERE条件）
            if ($key === 'id') {
                continue;
            }
            // 处理JSON字段（如 config.form.item_type）
            if (strpos($key, '.') !== false) {
                list($jsonField, $jsonPath) = explode('.', $key, 2);
                if (in_array("{$jsonField}.{$jsonPath}", $allowedJsonPaths)) {
                    $jsonUpdates[$jsonField][] = [
                        'path' => '$.' . str_replace('.', '.', $jsonPath),
                        'value' => $value
                    ];
                }
            } // 处理普通字段
            elseif (in_array($key, $allowedFields)) {
                $normalUpdate[$key] = $value;
            }
        }

        // 构建更新表达式
        $updateData = $normalUpdate;
        foreach ($jsonUpdates as $field => $paths) {
            $expression = $field;
            $bindParams = [];
            foreach ($paths as $path) {
                $expression = "JSON_SET({$expression}, '{$path['path']}', ?)";
                $bindParams[] = $path['value'];
            }
            $updateData[$field] = Db::raw($expression, $bindParams);
        }
        // 执行更新（带闭包事务保障原子性）
        Db::transaction(function () use ($data, $updateData) {
            $model = FieldModel::find($data['id']);
            if (!$model) {
                throw new \Exception('记录不存在');
            }
            $model->save($updateData);
        });
        return $this->success();
    }

    /**
     *  拖拽排序
     * @return \think\response\Json
     */
    #[Auth('dev:field:drag')]
    public function drag(): \think\response\Json
    {

        $fields = "newId,oldId,dragPos,orderBy";
        $data = $this->request->only(explode(',', $fields), 'post');
        SortableService::sort('dev_field', $data);
        return $this->success();

    }

    public function initFieldForm(): \think\response\Json
    {
        $menu_id = $this->request->post('menu_id');
        // 字段所在菜单
        $data['menu_info'] = Db::name('dev_menu')->find($menu_id);
        // 字段类型默认值
        $data['field_default'] = PropService::getFieldTypeDefault();
        // 获取系统多语言类型列表
        $data['languages'] = I18nService::getLangList();
        // 返回初始化编辑字段表单所需的数据
        return $this->success(['data' => $data]);
    }

    /**
     * 载入各种字段类型的默认配置
     * @return \think\response\Json
     */
    public function getDefaultConfig(): \think\response\Json
    {
        $list = Db::name('dev_prop')->field('value,config')
            ->where('type', '=', 'field')
            ->where('status', '=', 1)
            ->select()->toArray();
        $data = [];
        foreach ($list as $item) {
            $data[$item['value']] = $item['config'] ? json_decode($item['config'], true) : [];
        }
        return $this->success(['data' => $data]);
    }

    /**
     * 获取字段列表
     * @return \think\response\Json
     */
    public function getFieldList(): \think\response\Json
    {
        $menu_id = $this->request->post('menu_id/d');

        $fieldList = FieldModel::where(['menu_id' => $menu_id])
            ->order('sort', 'asc')
            ->select()
            ->toArray();
        return $this->success(['data' => $fieldList]);

    }

    /**
     * 检查表是否有数据
     * @return \think\response\Json
     */
    public function checkTableHasData(): \think\response\Json
    {
        $menu_id = $this->request->post('menu_id/d');
        $field = $this->request->post('field');

        // 查询菜单信息
        $menuInfo = MenuModel::find($menu_id);
        // 检查字段是否已经存在
        if (DatabaseService::hasField($menuInfo->table_name, $field, $menuInfo['connect'])) {
            $count = Db::name($menuInfo->table_name)->count($field);
        } else {
            $count = 0;
        }
        return $this->success(['data' => $count]);

    }

    /**
     * 获取多语言键名
     * @return \think\response\Json
     */
    public function getLanguageKey(): \think\response\Json
    {
        $menu_id = $this->request->post('menu_id');
        $field = $this->request->post('field');

        if (empty($menu_id) || empty($field)) {
            return $this->error(['msg' => Constants::E_COMMON_INVALID_PARAM]);
        }
        $key = '';
        $inBuildField = [
            'id',
            'remark',
            'sort',
            'status',
            'create_time',
            'update_time',
            'delete_time',
            'create_id',
            'update_id',
            'delete_id',
            'create_dept',
            'action'
        ];
        if (in_array($field, $inBuildField)) {
            $key = 'common.field.' . $field;
        } else {
            $menuInfo = Db::name('dev_menu')->where('id', $menu_id)->cache(60)->find();
            $menu_names = StrHelper::getMenuNames($menuInfo['controller']);
            if ($menuInfo['key']) {
                if ($menuInfo['app'] === 'admin') {
                    // menu.demo.my.my-date.field.
                    $key = $menu_names['field_lang_prefix'] . $field;
                }
                if ($menuInfo['app'] === 'api') {
                    // api.demo.my.my-date.field.
                    $key = $menu_names['field_lang_prefix'] . $field;
                }
            }
        }
        return $this->success(['data' => $key]);

    }

    /**
     * 获得字段的配置
     * @return \think\response\Json
     */
    public function getGridField(): \think\response\Json
    {

        $name = $this->request->post('name');
        $columns = FieldService::getGridColumnConfig($name);
        return $this->success(['data' => $columns]);

    }

    public function getSearchFields(): \think\response\Json
    {

        $name = $this->request->post('name');
        $columns = FieldService::getSearchFields($name);
        return $this->success(['data' => $columns]);

    }

    /**
     * 获得指定菜单的字典配置
     * @return \think\response\Json
     * @throws \Exception
     */
    public function getOptions(): \think\response\Json
    {
        $name = $this->request->pathinfo();
        $data = FieldService::getMenuOptions($name);
        return $this->success(['data' => $data]);
    }
}
